package com.xbongbong.paas.service.staff.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.xbongbong.app.enums.DailyWorkExcelEnum;
import com.xbongbong.i18n.util.I18nMessageUtil;
import com.xbongbong.paas.log.MongoLogHelp;
import com.xbongbong.paas.log.constant.LogMemoConstant;
import com.xbongbong.paas.log.thread.LogThreadPoolBeanConfig;
import com.xbongbong.paas.pojo.ExportStatusPojo;
import com.xbongbong.paas.pojo.dto.FormDataListDTO;
import com.xbongbong.paas.pojo.vo.ExportFormDataVO;
import com.xbongbong.paas.pojo.vo.ExportWorkStaffVO;
import com.xbongbong.paas.redis.PaasRedisHelper;
import com.xbongbong.paas.redis.RedisConstant;
import com.xbongbong.paas.redis.RedisPrefixConstant;
import com.xbongbong.paas.service.HandleImportService;
import com.xbongbong.paas.service.staff.StaffExcelNoFormService;
import com.xbongbong.paas.toolbox.exception.XbbException;
import com.xbongbong.paas.toolbox.util.BeanUtil;
import com.xbongbong.paas.toolbox.util.CollectionsUtil;
import com.xbongbong.paas.toolbox.util.DateTimeUtil;
import com.xbongbong.paas.toolbox.util.JsonHelperUtil;
import com.xbongbong.paas.toolbox.util.StringUtil;
import com.xbongbong.pro.constant.I18nStringConstant;
import com.xbongbong.pro.enums.ErrorCodeEnum;
import com.xbongbong.pro.enums.errorcodes.ImportErrorCodeEnum;
import com.xbongbong.pro.enums.errorcodes.SystemErrorCodeEnum;
import com.xbongbong.pro.weblist.pojo.WorkReportStatisicPojo;
import com.xbongbong.pro.weblist.pojo.dto.WorkReportStaticExportDTO;
import com.xbongbong.pro.weblist.pojo.dto.WorkReportStatisicDTO;
import com.xbongbong.pro.weblist.pojo.vo.WorkReportStatisicVO;
import com.xbongbong.saas.constant.BasicConstant;
import com.xbongbong.saas.constant.StringConstant;
import com.xbongbong.saas.constant.export.ExportConstant;
import com.xbongbong.saas.constant.export.ImportConstant;
import com.xbongbong.saas.enums.OperateModuleTypeEnum;
import com.xbongbong.saas.enums.OperateTypeEnum;
import com.xbongbong.saas.enums.RedundantTemplateTypeEnum;
import com.xbongbong.saas.service.WorkReportService;
import org.apache.poi.ss.usermodel.CellStyle;
import org.apache.poi.ss.usermodel.Font;
import org.apache.poi.ss.usermodel.HorizontalAlignment;
import org.apache.poi.ss.usermodel.VerticalAlignment;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.xssf.streaming.SXSSFCell;
import org.apache.poi.xssf.streaming.SXSSFRow;
import org.apache.poi.xssf.streaming.SXSSFSheet;
import org.apache.poi.xssf.streaming.SXSSFWorkbook;
import org.apache.poi.xssf.usermodel.XSSFFont;
import org.apache.poi.xssf.usermodel.XSSFRichTextString;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTSheetDimension;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.i18n.LocaleContextHolder;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Objects;

/**
 * @Author mingliang
 * @Description 非表单的导入导出
 * @Date 2022/4/8 14:53
 **/
@Service("staffExcelNoFormService")
public class StaffExcelNoFormServiceImpl implements StaffExcelNoFormService {
    private static final Logger LOG = LoggerFactory.getLogger(StaffExcelNoFormServiceImpl.class);

    @Resource
    private HandleImportService handleImportService;
    @Resource
    private PaasRedisHelper paasRedisHelper;
    @Resource
    private LogThreadPoolBeanConfig logThreadPoolBeanConfig;
    @Resource
    private MongoLogHelp mongoLogHelp;
    @Resource
    private WorkReportService workReportService;




    @Override
    public ExportWorkStaffVO exportDailyWork(WorkReportStaticExportDTO workReportStaticExportDTO) throws XbbException {
        ExportWorkStaffVO exportFormDataVO = new ExportWorkStaffVO();
        String userName = workReportStaticExportDTO.getLoginUserName();
        String corpid = workReportStaticExportDTO.getCorpid();
        String userId = workReportStaticExportDTO.getUserId();
        // 读取导出任务状态缓存
        String hashKey = corpid + "_" + userId;
        ExportStatusPojo exportStatusPojo = JsonHelperUtil.parseObject(paasRedisHelper.getValue(RedisPrefixConstant.EXPORT_STATUS_KEY, hashKey), ExportStatusPojo.class);
        if (exportStatusPojo != null && Objects.equals(exportStatusPojo.getFinish(), 2)) {
            // 上次导出任务未结束
            throw new XbbException(ImportErrorCodeEnum.API_ERROR_235004);
        }
        // 上次导出状态缓存清除
        paasRedisHelper.removeValue(RedisPrefixConstant.EXPORT_STATUS_KEY, hashKey);
        //塞个假进度条
        exportStatusPojo = new ExportStatusPojo(ExportConstant.EXPORT_MAX_TOTAL);
        paasRedisHelper.setValue(RedisPrefixConstant.EXPORT_STATUS_KEY, hashKey, exportStatusPojo, RedisConstant.SHORT_DURATION);
        // 处理数据
        WorkReportStatisicDTO workReportStatisicDTO = new WorkReportStatisicDTO();
        BeanUtil.copyProperties(workReportStaticExportDTO, workReportStatisicDTO);
        WorkReportStatisicVO workReportStatisicVO = workReportService.exportExcel(workReportStatisicDTO);
        List<WorkReportStatisicPojo> dataList = workReportStatisicVO.getList();
        if (CollectionsUtil.isEmpty(dataList)) {
            return exportFormDataVO;
        }
        exportDailyWorkData(workReportStaticExportDTO, dataList);
        // 打印日志
        if (dataList.size() > 0) {
            Runnable runnable = () -> {
                try {
                    OperateModuleTypeEnum operateModuleTypeEnum = OperateModuleTypeEnum.WORKREPORT;
                    String typeName = operateModuleTypeEnum.getName();
                    String memo = String.format(I18nMessageUtil.getMessage(LogMemoConstant.LOG_MEMO_WORK_REPORT_EXPORT), userName, typeName);
                    mongoLogHelp.buildLogWithoutAsync(corpid, userId, userName, operateModuleTypeEnum, OperateTypeEnum.EXPORT,
                            null, typeName, memo, workReportStaticExportDTO.getHttpHeader());
                } catch (XbbException e) {
                    LOG.error("com.xbongbong.paas.service.impl.PaasExcelServiceImpl.logForExportFormData error", e);
                }
            };
            logThreadPoolBeanConfig.sysLogThreadPool().execute(runnable);
        }

        return exportFormDataVO;
    }

    /**
     * 导出工作报告
     *
     * @param workReportStaticExportDTO
     * @param dataList
     * @throws XbbException
     */
    private ExportFormDataVO exportDailyWorkData(WorkReportStaticExportDTO workReportStaticExportDTO, List<WorkReportStatisicPojo> dataList) throws XbbException {
        ExportFormDataVO exportFormDataVO = new ExportFormDataVO();
        List<String> aliasSet = workReportStaticExportDTO.getAliasSet();
        String[] split = workReportStaticExportDTO.getLocale().split("_");
        LocaleContextHolder.setLocale(new Locale(split[0], split[1]));
        String hashKey = workReportStaticExportDTO.getCorpid() + "_" + workReportStaticExportDTO.getUserId();
        String menuName = RedundantTemplateTypeEnum.WORKREPORT.getName();
        Workbook workbook = null;
        try {
            String typeName = RedundantTemplateTypeEnum.WORKREPORT_DAILY.getName();
            if (Objects.equals(workReportStaticExportDTO.getReportType(), 1)) {
                typeName = RedundantTemplateTypeEnum.WORKREPORT_DAILY.getName();
            } else if (Objects.equals(workReportStaticExportDTO.getReportType(), 2)) {
                typeName = RedundantTemplateTypeEnum.WORKREPORT_WEEKLY.getName();
            } else if (Objects.equals(workReportStaticExportDTO.getReportType(), 3)) {
                typeName = RedundantTemplateTypeEnum.WORKREPORT_MONTHLY.getName();
            }
            //创建Excel对象
            workbook = createExcelByDailyWork(dataList, typeName, aliasSet);


            String excelName = menuName + DateTimeUtil.getString(DateTimeUtil.SDFDate) + ImportConstant.EXCEL_SUFFIX;
            exportFormDataVO.setWorkbook(workbook);
            exportFormDataVO.setName(excelName);
            // OSS上传文件
            FormDataListDTO formDataListDTO = new FormDataListDTO();
            BeanUtil.copyProperties(workReportStaticExportDTO, formDataListDTO);
            handleImportService.exportAsync(formDataListDTO, exportFormDataVO, ImportConstant.EXCEL_SUFFIX);
        } catch (XbbException e) {
            LOG.error("com.xbongbong.paas.help.PaasExcelExportHelp.exportSaasFormData error", e);
            ExportStatusPojo exportStatusPojo = JsonHelperUtil.parseObject(Objects.toString(paasRedisHelper.getValue(RedisPrefixConstant.EXPORT_STATUS_KEY, hashKey), JSON.toJSONString(new ExportStatusPojo())), ExportStatusPojo.class);
            exportStatusPojo.setFinish(1);
            exportStatusPojo.setErrorMsg(I18nMessageUtil.getMessage(I18nStringConstant.EXPORT_FAILED));
            paasRedisHelper.setValue(RedisPrefixConstant.EXPORT_STATUS_KEY, hashKey, exportStatusPojo, RedisConstant.SHORT_DURATION);
            throw e;
        } catch (Exception e) {
            LOG.error("paasExcel数据库导出表单数据出错", e);
            ExportStatusPojo exportStatusPojo = JsonHelperUtil.parseObject(Objects.toString(paasRedisHelper.getValue(RedisPrefixConstant.EXPORT_STATUS_KEY, hashKey), JSON.toJSONString(new ExportStatusPojo())), ExportStatusPojo.class);
            exportStatusPojo.setFinish(1);
            exportStatusPojo.setErrorMsg(I18nMessageUtil.getMessage(I18nStringConstant.EXPORT_FAILED));
            paasRedisHelper.setValue(RedisPrefixConstant.EXPORT_STATUS_KEY, hashKey, exportStatusPojo, RedisConstant.SHORT_DURATION);
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001);
        } finally {
            closeWorkBookException(workbook);
        }
        return exportFormDataVO;
    }


    /**
     * 关闭workbook
     * @param workbook
     */
    private void closeWorkBookException( Workbook workbook) {
        if (Objects.nonNull(workbook)) {
            try {
                workbook.close();
            } catch (IOException e1) {
                LOG.error("关闭workbook错误", e1);
            }catch (Exception e1) {
                LOG.error("关闭workbook错误", e1);
            }
        }
    }

    /**
     * @param dataList  查询出的数据
     * @param typeName  名称
     * @param aliasList 选中的列
     * @Author mingliang
     * @Description
     * @Date 2022/3/30 19:11
     **/
    private Workbook createExcelByDailyWork(List<WorkReportStatisicPojo> dataList, String typeName, List<String> aliasList) {
        // 导出状态
        int totalRowNum = dataList.size();
        Map<String, String> allEnumMap = DailyWorkExcelEnum.getAllEnumMap();
        Map<String, Integer> allEnumSort = DailyWorkExcelEnum.getAllEnumSort();
        JSONArray dataJsonArray = JSONArray.parseArray(JSON.toJSONString(dataList));
        List<List<String>> dataArrayList = new ArrayList<>();
        // 将aliasList进行排序
        for (int i = 0; i < aliasList.size(); i++) {
            for (int j = i + 1; j < aliasList.size(); j++) {
                String s = aliasList.get(i);
                String s1 = aliasList.get(j);
                Integer orDefault = allEnumSort.getOrDefault(s, -1);
                Integer orDefault1 = allEnumSort.getOrDefault(s1, -1);
                if (orDefault > orDefault1) {
                    aliasList.set(i, s1);
                    aliasList.set(j, s);
                }
            }
        }
        for (int i = 0; i < dataJsonArray.size(); i++) {
            List<String> tempList = new ArrayList<>();
            JSONObject jsonObject = dataJsonArray.getJSONObject(i);
            aliasList.forEach(e -> {
                String value = jsonObject.getString(e);
                if (StringUtil.isEmpty(value)) {
                    value = "";
                }
                tempList.add(value);
            });
            dataArrayList.add(tempList);
        }
        XSSFWorkbook workbook = new XSSFWorkbook();
        XSSFSheet xssfSheet = workbook.createSheet();
        CTSheetDimension dimension = xssfSheet.getCTWorksheet().getDimension();
        dimension.setRef("A1:A" + (aliasList.size()));
        SXSSFWorkbook wb = new SXSSFWorkbook(workbook, 500);
        SXSSFSheet sheet = wb.getSheetAt(0);
        // 样式对象
        CellStyle titleStyle = wb.createCellStyle();
        // 垂直
        titleStyle.setVerticalAlignment(VerticalAlignment.CENTER);
        // 水平
        titleStyle.setAlignment(HorizontalAlignment.CENTER);
        // 设置标题字体格式
        Font fontTitle = wb.createFont();
        // 设置字体大小
        fontTitle.setFontHeightInPoints(ImportConstant.FONT_SIZE);
        // 设置字体，是什么类型例如：Courier New
        fontTitle.setFontName(ImportConstant.FONT_COURIER_NEW);
        titleStyle.setFont(fontTitle);
        // 设置是否能够换行，能够换行为true
        titleStyle.setWrapText(false);

        SXSSFRow row1 = sheet.createRow(0);
        SXSSFCell cell = row1.createCell(0);
        cell.setCellStyle(titleStyle);
        cell.setCellValue(getFontTextString(I18nMessageUtil.getMessage(StringConstant.WORK_REPORT_STATISTICAL_TABLE), workbook));

        if (aliasList.size() > BasicConstant.ONE) {
            CellRangeAddress region = new CellRangeAddress(0, 0, 0, aliasList.size() - 1);
            sheet.addMergedRegion(region);
        }

        SXSSFRow row2 = sheet.createRow(1);
        int index = 0;
        for (String alias : aliasList) {
            row2.createCell(index).setCellValue(getFontTextString(allEnumMap.getOrDefault(alias, ""), workbook));
            index++;
        }
        // 记录Excel的行数
        int rowIntNum = sheet.getLastRowNum() + 1;
        for (int i = 0; i < totalRowNum; i++) {
            SXSSFRow row = sheet.createRow(rowIntNum);
            rowIntNum++;
            List<String> valueList = dataArrayList.get(i);
            for (int j = 0; j < valueList.size(); j++) {
                String value = valueList.get(j);
                row.createCell(j).setCellValue(getFontTextString(value, workbook));
            }
        }
        sheet.setDefaultColumnWidth(20);
        return wb;
    }

    /**
     * @param value
     * @param workbook
     * @Author mingliang
     * @Description 将字体修改
     * @Date 2022/4/1 9:53
     **/
    private XSSFRichTextString getFontTextString(String value, XSSFWorkbook workbook) {
        XSSFRichTextString richString = new XSSFRichTextString(value); //textValue是要设置大小的单元格数据
        XSSFFont font = workbook.createFont();
        font.setFontHeightInPoints((short) 12);//设置excel数据字体大小
        font.setFontName("宋体");
        richString.applyFont(font);
        return richString;
    }
}
